package com.example.myapplication;

import android.util.Log;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

public class TCPClient {
    private static final String TAG = "TCPClient";

    private String ip;
    private int port;

    private Socket mSocket;
    private SocketAddress mSocketAddress;
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    private DataInputStream mDataInputStream;
    private ReadThread mReadThread;
    private boolean _isConnected = false;
    private boolean syncDataFlag = false;
    private byte[] mData;

    TCPClient() {
    }

    private static final TCPClient tcpClient = new TCPClient();

    public static TCPClient getInstance() {
        return tcpClient;
    }

    public void setClient(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    public void connect() {
        try {
            Log.d(TAG, "connect: start");
            this.mSocket = new Socket();
//            this.mSocket.setKeepAlive(true); // TODO 确保TCP连接在长时间空闲的情况下不会被服务器或网络设备主动关闭
            this.mSocketAddress = new InetSocketAddress(ip, port);
            this.mSocket.connect(mSocketAddress, 2000);// 设置连接超时时间为2秒
            this.mOutputStream = mSocket.getOutputStream();
            this.mInputStream = mSocket.getInputStream();
            this.mDataInputStream = new DataInputStream(mSocket.getInputStream());

            this.mReadThread = new TCPClient.ReadThread();
            this.mReadThread.start();
            this._isConnected = true;

            Log.d(TAG, "connect: start");
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "connect: " + e);
            Log.d(TAG, "connect: fail");
        }
    }

    public String getData() throws InterruptedException {
        while (!syncDataFlag) {
            Thread.sleep(500);
        }
        // TODO syncDataFlag = false ?
        syncDataFlag = false;
//        return mData;
        return null;
    }

    public byte[] getState() throws InterruptedException {
        int count = 0;
        while (!syncDataFlag && count<50) {
            count++;
            Thread.sleep(20);
        }
        if(syncDataFlag == false){
            return (new byte[0]);
        }
        syncDataFlag = false;
        return mData;
    }

    public void close() {

        if (this.mReadThread != null) {
            this.mReadThread.interrupt();
        }
        if (this.mSocket != null) {
            try {
                this.mSocket.close();
                this.mSocket = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this._isConnected = false;
    }

    public boolean isConnected() {
        return this._isConnected;
    }

    public void send(TargetMsg targetMsg) {
        // TODO
        try {
            byte[] bytearray;
            bytearray = targetMsg.toBytes();
            this.mOutputStream.write(bytearray);
            System.out.println("send data to server");
            Log.d(TAG, "SyncScenarioEngine: write end");

        } catch (Exception e) {
            Log.e(TAG, "connect: " + e);
        }
    }

    public void sendRefresh() {
        try {
            byte[] bytearray;
            bytearray = TargetMsg.getRefresh();
            this.mOutputStream.write(bytearray);
            System.out.println("getRefresh");
            Log.d(TAG, "SyncScenarioEngine: getRefresh");

        } catch (Exception e) {
            Log.e(TAG, "connect: " + e);
        }
    }

    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                try {
                    if (TCPClient.this.mInputStream == null) {
                        return;
                    }
                    int available = 0;
                    while (available == 0) {
                        available = TCPClient.this.mDataInputStream.available();
                    }
                    if (available > 0) {
                        byte[] buffer = new byte[4]; // TODO 确定返回的消息长度
                        mDataInputStream.readFully(buffer);
                        mData = buffer;
                        syncDataFlag = true;
                    } else {
                        Thread.sleep(10);
                    }
                } catch (Throwable e) {
                    System.out.println(e.getMessage());
                    return;
                }
            }
        }
    }
}

